import { css } from '@emotion/react'
import { getLogger } from '@gnlab/utils'
import { Tag, Checkbox, Radio, Input, Button } from 'antd'
import throttle from 'lodash/throttle'
import AutoSizer from 'react-virtualized-auto-sizer'
import { FixedSizeList as List } from 'react-window'
import { EditModal } from '@/desktop/components'
import  defaultAvatar  from '@/desktop/assets/avatar.jpg'
import { useStreams } from '@/lib/utils'
import services from '@/services'
import {
  type InternalContact,
  searchInternals as requestSearchInternals,
} from '@/services/contact-types/internals'

const logger = getLogger('ui/choose-internals')

export interface ChooseContact {
  nickname: string
  userId: string
  avatar: string
  corpid: string
  corpname: string
}

export function ChooseInternalsModal(props: {
  open: boolean
  choosed?: ChooseContact[]
  onChoosed: (choosed: ChooseContact[]) => void
  onCancel: () => void
  extraItems?: ChooseContact[] // 附加的待选项，显示在最上面
  single?: boolean // 是否单选
  tips?: React.ReactNode // 要额外显示的提示信息
  emptyable?: boolean // 是否允许不选中联系人的情况下保存
}) {
  const { open, onCancel, ...restProps } = props
  return <EditModal open={open} title="选择员工" width={700} onCancel={onCancel}>
    {open ? <ChooseInternals onCancel={onCancel} {...restProps} /> : null}
  </EditModal>
}

export function ChooseInternals({
  choosed: initialChoosed,
  onChoosed,
  onCancel,
  extraItems,
  tips,
  single = false,
  emptyable = false,
}: {
  choosed?: ChooseContact[]
  onChoosed: (choosed: ChooseContact[]) => void
  onCancel: () => void
  extraItems?: ChooseContact[]
  tips?: React.ReactNode
  single?: boolean
  emptyable?: boolean
}) {
  const [qywxs, defaultInternals] = useStreams(services.qywxs.usables, services.internals.list)

  const [choosed, setChoosed] = useState(initialChoosed ?? [])
  const choosedIds = useMemo(() => new Set(choosed.map(v => v.userId)), [choosed])

  const [keyword, setKeyword] = useState('')
  const [searchedInternals, setSearchedInternals] = useState<InternalContact[] | null>(null)
  const searchInternals = useMemo(
    () =>
      throttle((keyword: string) => {
        if (!keyword) return void setSearchedInternals(null)

        // 一个员工仅在列表里出现一次，因此每个 corpid 挑选一个企业微信，保证不会拉取到重复的员工
        const corpids = new Set<string>()
        const wxids: string[] = []
        for (const qywx of qywxs.values()) {
          if (!corpids.has(qywx.corpid)) {
            corpids.add(qywx.corpid)
            wxids.push(qywx.wxid)
          }
        }

        void requestSearchInternals(wxids, keyword, 1, 1000).then(res => {
          if (res.success) {
            setSearchedInternals(res.data)
          } else {
            logger.error('搜索员工失败', res.error)
            setSearchedInternals([])
          }
        })
      }, 300),
    [qywxs],
  )
  useEffect(() => searchInternals(keyword), [searchInternals, keyword])

  const switchChoose = useCallback(
    (item: ChooseContact) => {
      if (single) {
        setChoosed(choosed => (choosed[0]?.userId !== item.userId ? [item] : []))
      } else {
        setChoosed(choosed =>
          !choosed.find(v => v.userId === item.userId)
            ? [...choosed, item]
            : choosed.filter(v => v.userId !== item.userId),
        )
      }
    },
    [single],
  )

  const save = useCallback(() => {
    onChoosed(choosed)
  }, [choosed, onChoosed])

  const internals: ChooseContact[] = useMemo(() => {
    let internals: InternalContact[]
    if (searchedInternals) internals = searchedInternals
    else {
      // 记录出现过的员工。同一个员工可能是多个企业微信的联系人，但只需要在列表里出现一次
      // Set<user_id>
      const exists = new Set<string>()
      internals = [...defaultInternals.values()].filter(ct => {
        const qywx = qywxs.get(ct.ownerWxid)
        const identity = `${ct.userId}-${qywx?.corpid ?? ''}`
        if (qywx && !exists.has(identity)) {
          exists.add(identity)
          return true
        } else {
          return false
        }
      })
    }
    return internals.map(ct => {
      const qywx = qywxs.get(ct.ownerWxid)!
      return {
        userId: ct.userId,
        nickname: ct.name,
        avatar: ct.avatar,
        corpid: qywx.corpid,
        corpname: qywx.corpname,
      }
    })
  }, [qywxs, defaultInternals, searchedInternals])

  const formattedList = useMemo(() => {
    return [...(extraItems ?? []), ...internals].map(ct => ({
      contact: ct,
      choosed: choosedIds.has(ct.userId),
      switchChoose: () => switchChoose(ct),
    }))
  }, [extraItems, internals, choosedIds, switchChoose])
  const RenderContactItem = useCallback(
    ({
      data,
      index,
      style,
    }: {
      data: typeof formattedList
      index: number
      style: React.CSSProperties
    }) => <ContactItem {...data[index]!} style={style} single={single} />,
    [single],
  )
  const itemKey = useCallback(
    (index: number, list: typeof formattedList) => list[index]!.contact.userId,
    [],
  )

  return <>
    <main css={styles.wrap}>
      <div css={styles.search}>
        <Input
          placeholder="输入关键词搜索"
          value={keyword}
          onChange={e => setKeyword(e.target.value)}
        />
        {tips}
      </div>
      <div css={styles.list}>
        <AutoSizer>
          {({ width, height }) => <List
            height={height}
            width={width}
            itemCount={formattedList.length}
            itemSize={59}
            itemData={formattedList}
            itemKey={itemKey}
          >
            {RenderContactItem}
          </List>}
        </AutoSizer>
      </div>
      {choosed.length ? (
        <div css={styles.choosed}>
          <label>当前选中：</label>
          <div className="list">
            {choosed.map((item, index) => <Tag
              key={`${item.userId}-${index}`}
              closable
              onClose={() => switchChoose(item)}
            >
              {item.nickname}
            </Tag>)}
          </div>
        </div>
      ) : null}
    </main>
    <footer>
      <Button onClick={onCancel}>取消</Button>
      <Button type="primary" disabled={!emptyable && !choosed.length} onClick={save}>
        保存
      </Button>
    </footer>
  </>
}

function ContactItem(props: {
  contact: ChooseContact
  choosed: boolean
  switchChoose: (ct: ChooseContact) => void
  style: React.CSSProperties
  single: boolean
}) {
  const { contact, choosed, switchChoose, style, single } = props
  return <div style={style} css={styles.contact} onClick={() => switchChoose(contact)}>
    {!single ? <Checkbox checked={choosed} /> : null}
    <img src={contact.avatar || defaultAvatar} />
    <div className="info">
      <div>{contact.nickname}</div>
      <div className="corp">{contact.corpname}</div>
    </div>
    {single ? <Radio checked={choosed} /> : null}
  </div>
}

const styles = {
  wrap: css`
    display: flex;
    flex-direction: column;
    height: 600px;
    max-height: 80vh;
    overflow: hidden;
  `,
  search: css`
    margin-bottom: 20px;
    flex-shrink: 0;
  `,
  list: css`
    flex: 1;
    overflow: hidden;
  `,
  contact: css`
    align-items: center;
    border-bottom: 1px solid #f0f0f0;
    cursor: pointer;
    display: flex;
    padding: 0 6px;
    &:hover {
      background-color: #fafafa;
    }
    .ant-checkbox-wrapper {
      margin-right: 1em;
    }
    img {
      border-radius: 2px;
      height: 45px;
      width: 45px;
    }
    .info {
      flex: 1;
      overflow: hidden;
      padding: 0 12px;
      & > * {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
    .corp {
      font-size: 12px;
      color: #999;
    }
  `,
  choosed: css`
    border-top: 1px solid #f0f0f0;
    margin-top: 20px;
    padding-top: 20px;
    display: flex;
    label {
      font-size: 13px;
      color: #777;
    }
    .list {
      flex: 1;
      display: flex;
      flex-wrap: wrap;
      row-gap: 8px;
    }
  `,
}
